use super::token::{Token, TokenPos, TokenType};
use crate::prelude::*;

pub struct Lexer {
    /// 源代码
    source: String,
    /// 字节视图
    bytes: Vec<u8>,
    /// 当前位置 -- 字节偏移量
    pos: usize,
    /// 当前行号 1-based
    line: usize,
    /// 当前列号 1-based
    column: usize,
}

impl Lexer {
    pub fn new(source: String) -> Self {
        let bytes = source.as_bytes().to_vec(); // 预先复制为 Vec<u8>
        Self {
            source,
            bytes,
            pos: 0,
            line: 1,
            column: 1,
        }
    }

    pub fn tokenize(&mut self) -> Result<Vec<Token>, CErr> {
        let mut tokens = Vec::new();
        loop {
            let token = self.next_token()?;
            let is_eof = token.is_eof();
            tokens.push(token);
            if is_eof {
                break;
            }
        }
        Ok(tokens)
    }

    pub fn next_token(&mut self) -> Result<Token, CErr> {
        self.skip_whitespace();

        if self.is_at_end() {
            let pos = TokenPos::new(self.line, self.column, self.pos, 0);
            return Ok(Token::simple(TokenType::Eof, pos));
        }

        let _start_pos = self.pos;
        let _start_line = self.line;
        let _start_column = self.column;

        let byte = self.cur_byte().unwrap();

        match byte {
            // 注释
            b'/' if self.peek_byte() == Some(b'/') => {
                self.skip_line_comment();
                self.next_token()
            }
            b'/' if self.peek_byte() == Some(b'*') => {
                self.skip_block_comment()?;
                self.next_token()
            }

            // 单字符
            b'(' => Ok(self.eat_single_char(TokenType::LParen)),
            b')' => Ok(self.eat_single_char(TokenType::RParen)),
            b'[' => Ok(self.eat_single_char(TokenType::LBrack)),
            b']' => Ok(self.eat_single_char(TokenType::RBrack)),
            b'{' => Ok(self.eat_single_char(TokenType::LBrace)),
            b'}' => Ok(self.eat_single_char(TokenType::RBrace)),
            b';' => Ok(self.eat_single_char(TokenType::Semi)),
            b',' => Ok(self.eat_single_char(TokenType::Comma)),
            b'+' => Ok(self.eat_single_char(TokenType::Plus)),
            b'-' => Ok(self.eat_single_char(TokenType::Minus)),
            b'*' => Ok(self.eat_single_char(TokenType::Star)),
            b'%' => Ok(self.eat_single_char(TokenType::Percent)),

            // 多字运算符
            b'=' => {
                if self.peek_byte() == Some(b'=') {
                    Ok(self.eat_double_char(TokenType::Eq))
                } else {
                    Ok(self.eat_single_char(TokenType::Assign))
                }
            }
            b'!' => {
                if self.peek_byte() == Some(b'=') {
                    Ok(self.eat_double_char(TokenType::Ne))
                } else {
                    Ok(self.eat_single_char(TokenType::Not))
                }
            }
            b'<' => {
                if self.peek_byte() == Some(b'=') {
                    Ok(self.eat_double_char(TokenType::Le))
                } else {
                    Ok(self.eat_single_char(TokenType::Lt))
                }
            }
            b'>' => {
                if self.peek_byte() == Some(b'=') {
                    Ok(self.eat_double_char(TokenType::Ge))
                } else {
                    Ok(self.eat_single_char(TokenType::Gt))
                }
            }
            b'&' => {
                if self.peek_byte() == Some(b'&') {
                    Ok(self.eat_double_char(TokenType::And))
                } else {
                    let start_pos = self.pos;
                    let start_line = self.line;
                    let start_column = self.column;
                    self.advance();
                    let pos = TokenPos::new(start_line, start_column, start_pos, 1);
                    Ok(Token::new(
                        TokenType::Error,
                        format!("Mysterious character \"&\"."),
                        pos,
                    ))
                }
            }
            b'|' => {
                if self.peek_byte() == Some(b'|') {
                    Ok(self.eat_double_char(TokenType::Or))
                } else {
                    let start_pos = self.pos;
                    let start_line = self.line;
                    let start_column = self.column;
                    self.advance();
                    let pos = TokenPos::new(start_line, start_column, start_pos, 1);
                    Ok(Token::new(
                        TokenType::Error,
                        format!("Mysterious character \"|\"."),
                        pos,
                    ))
                }
            }
            b'/' => Ok(self.eat_single_char(TokenType::Slash)),

            // 数字
            b'0'..=b'9' => self.scan_number(),

            // 小数点开头浮点数
            b'.' => {
                if let Some(next_byte) = self.peek_byte() {
                    if next_byte.is_ascii_digit() {
                        self.scan_float_start_dot()
                    } else {
                        let start_pos = self.pos;
                        let start_line = self.line;
                        let start_column = self.column;
                        self.advance();
                        let pos = TokenPos::new(start_line, start_column, start_pos, 1);
                        Ok(Token::new(
                            TokenType::Error,
                            format!("Mysterious character \".\"."),
                            pos,
                        ))
                    }
                } else {
                    let start_pos = self.pos;
                    let start_line = self.line;
                    let start_column = self.column;
                    self.advance();
                    let pos = TokenPos::new(start_line, start_column, start_pos, 1);
                    Ok(Token::new(
                        TokenType::Error,
                        format!("Mysterious character \".\"."),
                        pos,
                    ))
                }
            }

            // 标识符/关键字
            b'a'..=b'z' | b'A'..=b'Z' | b'_' => self.scan_ident(),

            // 其他字符
            _ => {
                let start_pos = self.pos;
                let start_line = self.line;
                let start_column = self.column;
                let ch = byte as char;
                self.advance();
                let pos = TokenPos::new(start_line, start_column, start_pos, 1);
                Ok(Token::new(
                    TokenType::Error,
                    format!("Mysterious character \"{}\".", ch),
                    pos,
                ))
            }
        }
    }

    fn skip_whitespace(&mut self) {
        while let Some(byte) = self.cur_byte() {
            if byte.is_ascii_whitespace() {
                self.advance();
            } else {
                break;
            }
        }
    }

    fn skip_line_comment(&mut self) {
        while let Some(byte) = self.cur_byte() {
            self.advance();
            if byte == b'\n' {
                break;
            }
        }
    }

    fn skip_block_comment(&mut self) -> CEResult<()> {
        self.advance(); // 消费 /
        self.advance(); // 消费 *

        loop {
            match self.cur_byte() {
                // 1. 文件末尾: 说明注释未正常关闭
                None => {
                    return Err(self.make_error("Unterminated block comment"));
                }
                // 2. 看到 *: 有可能是注释结尾
                Some(b'*') => {
                    self.advance(); // 先吃 *
                    // 看看 * 后面是不是 /
                    if self.cur_byte() == Some(b'/') {
                        self.advance(); // 是/，吃掉它，大功告成
                        return Ok(());
                    }
                    // 如果不是 /，继续下一次循环
                    // 原因: 因为已经吃掉了*，所以不会死循环
                }
                // 3. 看到任何其他字符，直接吃掉
                Some(_) => {
                    self.advance();
                }
            }
        }
    }

    /// 扫描数字
    fn scan_number(&mut self) -> Result<Token, CErr> {
        let start_pos = self.pos;
        let start_line = self.line;
        let start_column = self.column;
        let mut is_float = false;

        // 检查是否以 0 开头
        if self.cur_byte() == Some(b'0') {
            // 十六进制
            if self.peek_byte() == Some(b'x') || self.peek_byte() == Some(b'X') {
                return self.scan_hex_number();
            }
            // 八进制或数字0
            else {
                self.advance(); // 消费 0

                // 检查后面是否是八进制数字
                while let Some(byte) = self.cur_byte() {
                    if byte >= b'0' && byte <= b'7' {
                        self.advance();
                    } else if byte == b'8' || byte == b'9' {
                        // FIX: 临时在遇到 8 , 9 停止扫描，让0成为一个单独的token
                        // 8, 9 将在下次调用时被识别为新的token
                        break;
                    } else {
                        break;
                    }
                }
            }
        } else {
            // 十进制整数部分
            while let Some(byte) = self.cur_byte() {
                if byte.is_ascii_digit() {
                    self.advance();
                } else {
                    break;
                }
            }
        }

        // 小数
        if self.cur_byte() == Some(b'.') {
            if let Some(next_byte) = self.peek_byte() {
                if next_byte.is_ascii_digit() || next_byte == b'e' || next_byte == b'E' {
                    is_float = true;
                    self.advance(); // consume '.'
                    while let Some(byte) = self.cur_byte() {
                        if byte.is_ascii_digit() {
                            self.advance();
                        } else {
                            break;
                        }
                    }
                } else {
                    is_float = true;
                    self.advance(); // consume '.' for cases like "1."
                }
            } else {
                is_float = true;
                self.advance(); // consume '.' for cases like "1." at EOF
            }
        }

        // 科学计数法
        if self.cur_byte() == Some(b'e') || self.cur_byte() == Some(b'E') {
            is_float = true;
            self.advance(); // consume 'e' or 'E'
            if self.cur_byte() == Some(b'+') || self.cur_byte() == Some(b'-') {
                self.advance();
            }
            while let Some(byte) = self.cur_byte() {
                if byte.is_ascii_digit() {
                    self.advance();
                } else {
                    break;
                }
            }
        }

        let end_pos = self.pos;
        let text = self.source[start_pos..end_pos].to_string();
        let len = end_pos - start_pos;
        let pos = TokenPos::new(start_line, start_column, start_pos, len);
        let kind = if is_float {
            TokenType::FloatLit
        } else {
            TokenType::IntLit
        };
        Ok(Token::new(kind, text, pos))
    }

    /// 十六进制数
    fn scan_hex_number(&mut self) -> Result<Token, CErr> {
        let start_pos = self.pos;
        let start_line = self.line;
        let start_column = self.column;

        self.advance(); // 0
        self.advance(); // x or X

        let mut has_mantissa_digits = false;

        // 可选： 整数部分
        while let Some(byte) = self.cur_byte() {
            if byte.is_ascii_hexdigit() {
                self.advance();
                has_mantissa_digits = true;
            } else {
                break;
            }
        }

        let mut is_float = false;

        // 可选： 小数部分
        if self.cur_byte() == Some(b'.') {
            is_float = true;
            self.advance(); // consume '.'
            while let Some(byte) = self.cur_byte() {
                if byte.is_ascii_hexdigit() {
                    self.advance();
                    has_mantissa_digits = true;
                } else {
                    break;
                }
            }
        }

        // 在 0x / 0x. 后必须有数字
        if !has_mantissa_digits {
            return Err(self.make_error("Malformed hexadecimal number: no digits found"));
        }

        // 二进制指数部分
        if self.cur_byte() == Some(b'p') || self.cur_byte() == Some(b'P') {
            is_float = true;
            self.advance(); // consume 'p' or 'P'

            // 可选符号
            if self.cur_byte() == Some(b'+') || self.cur_byte() == Some(b'-') {
                self.advance();
            }

            let mut has_exponent_digits = false;
            while let Some(byte) = self.cur_byte() {
                if byte.is_ascii_digit() {
                    self.advance();
                    has_exponent_digits = true;
                } else {
                    break;
                }
            }
            if !has_exponent_digits {
                return Err(self.make_error(
                    "Malformed hexadecimal float: no exponent digits found after 'p'",
                ));
            }
        } else if is_float {
            // 十六进制数有小数点必须有 p 指数
            return Err(self.make_error("Malformed hexadecimal float: missing 'p' exponent"));
        }

        let end_pos = self.pos;
        let text = self.source[start_pos..end_pos].to_string();
        let len = end_pos - start_pos;
        let pos = TokenPos::new(start_line, start_column, start_pos, len);

        let kind = if is_float {
            TokenType::FloatLit
        } else {
            TokenType::IntLit
        };

        Ok(Token::new(kind, text, pos))
    }

    /// FIX: 小数点开头的浮点数
    fn scan_float_start_dot(&mut self) -> Result<Token, CErr> {
        let start_pos = self.pos;
        let start_line = self.line;
        let start_column = self.column;

        self.advance(); // consume '.'

        while let Some(byte) = self.cur_byte() {
            if byte.is_ascii_digit() {
                self.advance();
            } else {
                break;
            }
        }

        if self.cur_byte() == Some(b'e') || self.cur_byte() == Some(b'E') {
            self.advance();
            if self.cur_byte() == Some(b'+') || self.cur_byte() == Some(b'-') {
                self.advance();
            }
            while let Some(byte) = self.cur_byte() {
                if byte.is_ascii_digit() {
                    self.advance();
                } else {
                    break;
                }
            }
        }

        let end_pos = self.pos;
        let text = self.source[start_pos..end_pos].to_string();
        let len = end_pos - start_pos;
        let pos = TokenPos::new(start_line, start_column, start_pos, len);
        Ok(Token::new(TokenType::FloatLit, text, pos))
    }

    /// 标识符/关键字
    fn scan_ident(&mut self) -> Result<Token, CErr> {
        let start_pos = self.pos;
        let start_line = self.line;
        let start_column = self.column;

        while let Some(byte) = self.cur_byte() {
            if byte.is_ascii_alphanumeric() || byte == b'_' {
                self.advance();
            } else {
                break;
            }
        }

        let end_pos = self.pos;
        let text_slice = &self.source[start_pos..end_pos];
        let len = end_pos - start_pos;
        let pos = TokenPos::new(start_line, start_column, start_pos, len);

        let token_type = match text_slice {
            "int" => TokenType::Int,
            "float" => TokenType::Float,
            "void" => TokenType::Void,
            "const" => TokenType::Const,
            "if" => TokenType::If,
            "else" => TokenType::Else,
            "while" => TokenType::While,
            "break" => TokenType::Break,
            "continue" => TokenType::Continue,
            "return" => TokenType::Return,
            _ => TokenType::Ident,
        };

        Ok(Token::new(token_type, text_slice.to_string(), pos))
    }

    fn eat_single_char(&mut self, token_type: TokenType) -> Token {
        let start_pos = self.pos;
        let start_line = self.line;
        let start_column = self.column;
        self.advance();
        let text = self.source[start_pos..self.pos].to_string();
        let pos = TokenPos::new(start_line, start_column, start_pos, 1);
        Token::new(token_type, text, pos)
    }

    fn eat_double_char(&mut self, token_type: TokenType) -> Token {
        let start_pos = self.pos;
        let start_line = self.line;
        let start_column = self.column;
        self.advance();
        self.advance();
        let text = self.source[start_pos..self.pos].to_string();
        let pos = TokenPos::new(start_line, start_column, start_pos, 2);
        Token::new(token_type, text, pos)
    }

    fn advance(&mut self) {
        if let Some(byte) = self.cur_byte() {
            if byte == b'\n' {
                self.line += 1;
                self.column = 1;
            } else {
                self.column += 1;
            }
            self.pos += 1;
        }
    }

    #[inline(always)]
    fn cur_byte(&self) -> Option<u8> {
        self.bytes.get(self.pos).copied()
    }

    #[inline(always)]
    fn peek_byte(&self) -> Option<u8> {
        self.bytes.get(self.pos + 1).copied()
    }

    #[inline(always)]
    fn is_at_end(&self) -> bool {
        self.pos >= self.bytes.len()
    }

    fn make_error(&self, msg: &str) -> CErr {
        CErr::lexer_err(self.line, self.column, msg)
    }
}
